

#include "command.h"
#include "jCal.h"
#include "Task.h"
const string MESSAGE_WELCOME = "Welcome to jCal++!\n";
const string MESSAGE_COMMAND = "Enter Command: ";
const string MESSAGE_INVALID_COMMAND = "Command format is not valid!";
const string MESSAGE_TASK_NO_FOUND = "Task not found!";

const string SPACE = " ";
const string SLASH = "/";
const string FULL_STOP = ".";
const string HYPHEN = "-";
const string COLON = ":";
const string MORNING = "am";
const string AFTERNOON = "pm";

//Reserved for Messages
//const string jCal::MESSAGE_......	

/*=============================================================================================================
*
* 1. Functions below are used for command parsing, string comparison, etc. 
* 2. Please replace the them if they are provided in the c++ library.
* 
*/

bool command::equalsIgnoreCase(const string& str1, const string& str2) {
	if (str1.size() != str2.size()) {
		return false;
	}

	for (string::const_iterator c1 = str1.begin(), c2 = str2.begin(); c1 != str1.end(); ++c1, ++c2) {
		if (tolower(*c1) != tolower(*c2)) {
			return false;
		}
	}
	return true;
}

vector<string> command::spliter(string command, string delimiter) {
	vector<string> subStr;
	int pos = 0;
	string token;
	int i = 0;

	if(command.find(delimiter) == -1) {
		subStr.push_back(command);
		return subStr;
	}

	while ((pos = command.find(delimiter)) != -1) {
		if(pos == 0) {
			command.erase(0, pos + delimiter.length());
		} else {
			token = command.substr(0, pos);
			subStr.push_back(token);
			i++;
			command.erase(0, pos + delimiter.length());
		}
	}

	subStr.push_back(command);
	return subStr;

}

string command::removeEnd(string str, string rmv) {
	if (str.substr(str.size() - rmv.size()) == rmv ) {
		str = str.substr(0, str.size() - rmv.size());
	}

	return str;
}

string command::concat(string str1, string str2) {
	return str1+str2;
}

//possible date formats: DD/MM/YY or DD.MM.YY
int* command::dateParse(string date) {
	vector<string> subStr;
	string delimiter;
	int* temp = new int[3];
	int i;

	if(date.find(SLASH) != -1) {
		delimiter = SLASH;
	} else {
		delimiter = FULL_STOP;
	}

	subStr = spliter(date, delimiter);

	for(i = 0; i < 3; i ++) {
		temp[i] = atoi(subStr[i].c_str());
	}
	return temp;
}

/* possible time formate examples: (24hr)  14-16 or 14 or 14:30 or 14:30-16:45
*								   (12hr)  6am-8am or 6am or 6:30am-8:20pm or 6am-8 or 6:30-8:20pm or 6-8 or 8
* Time parsing is case-sensitive.
* The time is on the hour by default.
* Program assumes both "am" or both "pm" if it is only specified in either start time or end time.	
* ############### The function should assign current am/pm if not specified. Here it is am by default ##################
* ############### i.e. if input is "4-6", the program will assume 4am-6am by default ###################################
*/
int* command::timeParse(string time) {
	vector<string> subStr;
	vector<string> subStrTmp1;
	string subStrTmp2 = "";
	string delimiter;
	int* temp = new int[4];
	unsigned int i;

	subStrTmp1 = spliter(time, HYPHEN);

	for(i = 0; i < subStrTmp1.size(); i++) {
		subStrTmp1[i] = concat(subStrTmp1[i]," ");
		subStrTmp2 = concat(subStrTmp2, subStrTmp1[i]);
	}
	subStrTmp1.clear();
	subStrTmp1 = spliter(subStrTmp2, COLON);
	subStrTmp2 ="";

	for(i = 0; i < subStrTmp1.size(); i++) {
		subStrTmp1[i] = concat(subStrTmp1[i]," ");
		subStrTmp2 = concat(subStrTmp2, subStrTmp1[i]);
	}
	subStrTmp1.clear();
	subStrTmp1 = spliter(subStrTmp2, MORNING);
	subStrTmp2 ="";

	for(i = 0; i < subStrTmp1.size(); i++) {
		subStrTmp1[i] = concat(subStrTmp1[i]," ");
		subStrTmp2 = concat(subStrTmp2, subStrTmp1[i]);
	}
	subStrTmp1.clear();
	subStrTmp1 = spliter(subStrTmp2, AFTERNOON);
	subStrTmp2 ="";

	for(i = 0; i < subStrTmp1.size(); i++) {
		subStrTmp1[i] = concat(subStrTmp1[i]," ");
		subStrTmp2 = concat(subStrTmp2, subStrTmp1[i]);
	}

	for(i = 0; i < 6; i++) {
		subStrTmp2 = removeEnd(subStrTmp2, " ");
	}

	subStr = spliter(subStrTmp2, " ");

	if(subStr.size() == 1) {
		temp[0] = atoi(subStr[0].c_str());
		temp[1] = 0;
		temp[2] = 0;
		temp[3] = 0;
		if(time.find("pm") != -1) {
			temp[0] += 12;
		}
		return temp;	
	} else if(subStr.size() == 2) {
		temp[0] = atoi(subStr[0].c_str());
		temp[1] = 0;
		temp[2] = atoi(subStr[1].c_str());
		temp[3] = 0;
	} else {
		temp[0] = atoi(subStr[0].c_str());
		temp[1] = atoi(subStr[1].c_str());
		temp[2] = atoi(subStr[2].c_str());
		temp[3] = atoi(subStr[3].c_str());
	}


	if(time.find("am") != -1) {
		if(time.find("pm") != -1) {
			if(time.find("am") < time.find("pm")) {
				temp[2] += 12;
			} else {
				temp[0] += 12;
			}
		}
	} else {
		if(time.find("pm") != -1) {
			temp[0] += 12;
			temp[2] += 12;
		}
	}

	return temp;
}

/*==============================================================================================================
*
* Other minor functions used are defined here
*
*/

int* command::startToEnd(int startTime[]) {

	int* endTime = new int[4];
	endTime[0] = 0;
	endTime[1] = 0;
	endTime[2] = startTime[0];
	endTime[3] = startTime[1];

	return endTime;
}

int* command::endToStart(int endTime[]) {

	int* startTime = new int[4];
	startTime[0] = endTime[2];
	startTime[1] = endTime[3];
	startTime[2] = 0;
	startTime[3] = 0;

	return endTime;
}

int* command::getDate() {

	time_t rawtime;
	struct tm  timeinfo;
	char buffer[80];
	int* date = new int[3];

	vector<string> temp;
	time (&rawtime);
	localtime_s(&timeinfo, &rawtime);

	strftime(buffer,80,"%d-%m-%Y %I:%M:%S",&timeinfo);
	std::string str(buffer);

	temp = spliter(str, HYPHEN);

	for( int i = 0; i < 3; i++) {
		date[i] = atoi(temp[i].c_str());
	}

	return date;

}

int* command::getTime() {

	time_t rawtime;
	struct tm  timeinfo;
	char buffer[80];
	int* currTime = new int[2];
	string tempStr;

	vector<string> temp;
	time (&rawtime);
	localtime_s(&timeinfo, &rawtime);

	strftime(buffer,80,"%d-%m-%Y %I:%M:%S",&timeinfo);
	std::string str(buffer);

	temp = spliter(str, COLON);
	currTime[1] = atoi(temp[1].c_str());

	tempStr = temp[0];
	temp.clear();
	temp = spliter(tempStr, SPACE);
	currTime[0] = atoi(temp[1].c_str());

	return currTime;

}

void command::showToUser(string output) {
	cout << output;
}

void test() {

	/*===========testing addParse==========
	vector<string> a;
	a[0] = "eat";
	command::addParse(a);
	//====================================*/


	/*===========testing getTime/Date=======
	int* a = command::getTime();
	for(int i = 0; i < 2; i++) {
	cout << a[i] << endl;
	}
	//====================================*/


	/*============testing timeParse==========
	string a = "4:30pm-6:20am";
	//string a = "4pm";
	int* b = command::timeParse(a);
	for(int i = 0; i < sizeof(b); i++) {   
	cout << b[i] << endl;
	}
	//======================================*/

	/*=============testing dateParse=========
	//string a = "25.12.2014";
	string a = "25/12/2014";
	int* b = command::dateParse(a);
	for(int i = 0; i < sizeof(b) -1; i++) {   //sizeof(b) = 4, quite strange
	cout << b[i] << endl;
	}
	//========================================*/

	/*=======testing removeEnd============

	string a = "aaaaaaa       ";
	string b = command::removeEnd(a, " ");
	cout << strlen(b.c_str()) << endl;
	//==================================*/

	/*=======testing spliter=========
	string a = "aaaaa/aaaa/aa/a";
	vector<string> b = command::spliter(a, SLASH);

	for(int i= 0; i < b.size(); i++) {
	cout << b[i] << endl;
	}
	//==================================*/

	/*=======testing Task class=========
	int a[3] = {2, 2, 2};
	int *c;
	Task b;
	b.setDate(a);

	c = b.getDate();

	for(int i = 0; i < 3; i ++) {
	cout << c[i] << " ";
	}

	cout << endl;
	==================================*/
}

//==============================================================================================================

/*int command(int argc, char* argv[]) {

	command::showToUser(MESSAGE_WELCOME);

	//test();

	// Task newtask;

	while (true) {
		command::showToUser(MESSAGE_COMMAND);
		vector<string> userCommand(argv, argv+argc);
		if(userCommand[0] == "jCal++.exe") {
			userCommand.erase(userCommand.begin());
		}
		//cout << userCommand[0];
		command::executeCommand(userCommand);
	}
}
*/
void command::executeCommand(vector<string> command) {

	string commandTypeString = command[0];
	command.erase(command.begin());
	vector<string> commandDetailString = command;

	COMMAND_TYPE commandType = determineCommandType(commandTypeString);

	switch (commandType) {
	case LOGIN:
		login(commandDetailString);
		break;
	case LOGOFF:
		logoff();
		break;
	case ADD: 
		addParse(commandDetailString);
		break;
	case UPDATE:
		updateParse(commandDetailString);
		break;
	case DELETE:
		deleteParse(commandDetailString);
		break;
	case SEARCH:
		//only one word search is allowed
		if(sizeof(commandDetailString) == 1) {
			search(commandDetailString[0]);
		} else {
			showToUser(/*undefined message here*/"a");
		}
		break;
	case SORT:
		//sort();//Error here since sort() is not accessible
		break;
	case VIEW:
		view(commandDetailString);
		break;
	case HELP:
		//only one command help is allowed
		if(sizeof(commandDetailString) == 1) {
			help(commandDetailString[0]);
		} else if (sizeof(commandDetailString) == 0) {
			helpAll();
		}
		break;
	case INVALID:
		//undefined invalid message
		break;
	case EXIT:
		exit(0);
		break;
	default:
		//throw an error if the command is not recognized
		throw new exception("Unrecognized command type");
	}

}

command::COMMAND_TYPE command::determineCommandType(string command) {

	if(equalsIgnoreCase(command, "login")) {
		return COMMAND_TYPE::LOGIN;
	} else if (equalsIgnoreCase(command, "logoff")) {
		return COMMAND_TYPE::LOGOFF;
	} else if (equalsIgnoreCase(command, "add")) {
		return COMMAND_TYPE::ADD;
	} else if (equalsIgnoreCase(command, "update")) {
		return COMMAND_TYPE::UPDATE;
	} else if (equalsIgnoreCase(command, "delete")) {
		return COMMAND_TYPE::DELETE;
	} else if (equalsIgnoreCase(command, "search")) {
		return COMMAND_TYPE::SEARCH;
	} else if (equalsIgnoreCase(command, "sort")) {
		return COMMAND_TYPE::SORT;
	} else if (equalsIgnoreCase(command, "view")) {
		return COMMAND_TYPE::VIEW;
	} else if (equalsIgnoreCase(command, "help")) {
		return COMMAND_TYPE::HELP;
	} else if (equalsIgnoreCase(command, "exit")) {
		return COMMAND_TYPE::EXIT;
	} else {
		return COMMAND_TYPE::INVALID;
	}
}

//assumption: the access function wil return the task at index
Task command::access(int index) {
	
	 Task a= Task::Task () ;
return a;
}

//assumption: the search function will return the index of the task name given
//			  if the task is not found, the function will return 0
int* command::search(string item) {

	Task a = Task::Task() ;
return a.getIndex();

}

void command::view(vector<string> command) {

}

/*=====================notes for login metod==========================
* 
* I didn't add the rememberMe & rememberMePeriod features because:
* 
* It is hard to implement this feature and this feature is not really necessary.
* If we add in this feature, we must also provide a way to cancel rememberMe
*
*==================================================================== */
void command::login(vector<string> userInfo) {



}	

void command::logoff() {

}

//help will only display detailed instructions & examples for one command
void command::help(string helpCommand) {


}

//helpAll will display brief instructions for all possible commands
void command::helpAll() {


}




//command parsing functions

/* This method parses the add command
* Example: Add dinner with Chengyi/Chat about Dota2 -str 12.25.2014 6pm-8pm
* Assumptions: 1. no space in front of or after "/", space in front of and after "-str"
*			    2. space in front of/behind "-str" and other similar commands
*/
string command::addParse(vector<string> command) {
	Task temp;
	Task accessTask;
	string tempTaskName = command[0];	
	string tempTime;
	string tempDate;
	int* index;
	unsigned int i;
	//if descriptions of the task is given, separate the name and description.
	for(i = 1; i < command.size(); i++) {
		//-str means starting
		if(command[i] == "-str") {
			if(command.size() - i == 3) {
				temp.setDate(dateParse(command[i+1]));
				temp.setTime(timeParse(command[i+2]));
			} else if(command.size() - i == 2) {
				temp.setTime(timeParse(command[i+1]));
				temp.setDate(getDate());
			} else {
				showToUser(MESSAGE_INVALID_COMMAND);
			}
			break;
		}
		//-am means after(time)
		//I assume the "-str 6pm" (starting from 6pm) and "-am 6pm" (after 6pm) are the same.
		//They are both 1 hour by default
		else if(command[i] == "-am") {
			if(sizeof(command) - i == 3) {
				temp.setDate(dateParse(command[i+1]));
				temp.setTime(timeParse(command[i+2]));
			} else if(sizeof(command) - i == 2) {
				temp.setTime(timeParse(command[i+1]));
				temp.setDate(getDate());
			} else {
				showToUser(MESSAGE_INVALID_COMMAND);
			}
			break;
		}
		//-bm means before(time)
		else if(command[i] == "-bm") {
			if(command.size() - i == 3) {
				temp.setDate(dateParse(command[i+1]));
				temp.setTime(startToEnd(timeParse(command[i+2])));
			} else if(command.size() - i == 2) {
				temp.setTime(startToEnd(timeParse(command[i+2])));
				temp.setDate(getDate());
			} else {
				showToUser(MESSAGE_INVALID_COMMAND);
			}
			break;
		}
		//-an means after(event)
		else if(command[i] == "-an") {

			index = search(command[i+1]);

			if(index[0] == 0) {
				showToUser(MESSAGE_TASK_NO_FOUND);
			} else {
				accessTask = access(index[0]);
				temp.setDate(accessTask.getDate());
				temp.setTime(endToStart(timeParse(command[i+2])));
			}
			break;

		}
		//-bn means before(event)
		else if(command[i] == "-bn") {

			index = search(command[i+1]);

			if(index[0] == 0) {
				showToUser(MESSAGE_TASK_NO_FOUND);
			} else {
				accessTask = access(index[0]);
				temp.setDate(accessTask.getDate());
				temp.setTime(startToEnd(timeParse(command[i+2])));
			}
			break;

		} else {
			tempTaskName = concat(tempTaskName, command[i]);
		}

		if(tempTaskName.find(SLASH) == -1) {
			temp.setName(tempTaskName);
		} else {
			vector<string> nameAndDes = spliter(tempTaskName, SLASH);  
			temp.setName(nameAndDes[0]);
			temp.setDescription(nameAndDes[1]);
		} 
	}
	//addTask(temp);
    return temp.toString();
}


void command::updateParse(vector<string> command) {
	int* pos;
	int* index;
	Task temp;
	Task accessTask;
	string tempTaskName = command[0];
	vector<string> nameAndDes;	
	string tempTime;
	string tempDate;
	unsigned int i;


	if(tempTaskName.find(SLASH) == -1) {
		pos = search(tempTaskName);
		nameAndDes[1] = "";
	} else {
		nameAndDes = spliter(tempTaskName, SLASH);  
		pos = search(nameAndDes[0]);
	} 

	if(pos[0] == 0) {
		showToUser(MESSAGE_TASK_NO_FOUND);
	} else {
		temp = access(pos[0]);

		//below is the same code chunk as updateParse.
		/*if descriptions of the task is given, separate the name and description.
		for(int i = 1; i < sizeof(command); i++) {
		//-str means starting
		if(command[i] == "-str") {
		if(sizeof(command) - i == 3) {
		temp.setDate(dateParse(command[i+1]));
		temp.setTime(timeParse(command[i+2]));
		} else if(sizeof(command) - i == 2) {
		temp.setTime(timeParse(command[i+1]));
		temp.setDate(getDate());
		} else {
		showToUser(MESSAGE_INVALID_COMMAND);
		}
		break;
		}
		//-am means after(time)
		//I assume the "-str 6pm" (starting from 6pm) and "-am 6pm" (after 6pm) are the same.
		//They are both 1 hour by default
		else if(command[i] == "-am") {
		if(sizeof(command) - i == 3) {
		temp.setDate(dateParse(command[i+1]));
		temp.setTime(timeParse(command[i+2]));
		} else if(sizeof(command) - i == 2) {
		temp.setTime(timeParse(command[i+1]));
		temp.setDate(getDate());
		} else {
		showToUser(MESSAGE_INVALID_COMMAND);
		}
		break;
		}
		//-bm means before(time)
		else if(command[i] == "-bm") {
		if(sizeof(command) - i == 3) {
		temp.setDate(dateParse(command[i+1]));
		temp.setTime(startToEnd(timeParse(command[i+2])));
		} else if(sizeof(command) - i == 2) {
		temp.setTime(startToEnd(timeParse(command[i+2])));
		temp.setDate(getDate());
		} else {
		showToUser(MESSAGE_INVALID_COMMAND);
		}
		break;
		}
		//-an means after(event)
		else if(command[i] == "-an") {

		index = search(command[i+1]);

		if(index[0] == 0) {
		showToUser(MESSAGE_TASK_NO_FOUND);
		} else {
		accessTask = access(index[0]);
		temp.setDate(accessTask.getDate());
		temp.setTime(endToStart(timeParse(command[i+2])));
		}

		}
		//-bn means before(event)
		else if(command[i] == "-bn") {

		index = search(command[i+1]);

		if(index[0] == 0) {
		showToUser(MESSAGE_TASK_NO_FOUND);
		} else {
		accessTask = access(index[0]);
		temp.setDate(accessTask.getDate());
		temp.setTime(startToEnd(timeParse(command[i+2])));
		}

		} else {
		tempTaskName = concat(tempTaskName, command[i]);
		}

		if(tempTaskName.find(SLASH) == -1) {
		temp.setName(tempTaskName);
		} else {
		vector<string> nameAndDes = spliter(tempTaskName, SLASH);  
		temp.setName(nameAndDes[0]);
		temp.setDescription(nameAndDes[1]);
		} 
		}
		*/
	}


	//updateTask(temp, pos);
}

//################ change the project manual: do not use ##################
//################ periodic events!!! #####################################
void command::deleteParse(vector<string> command) {
	int* pos;

	pos = search(command[0]);

	if(pos[0] == 0) {
		showToUser(MESSAGE_TASK_NO_FOUND);
	} else {
		//deleteTask(pos);
	}

}

void command::viewParse(vector<string> command){

}





